/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | foam-extend: Open Source CFD
   \\    /   O peration     | Version:     4.1
    \\  /    A nd           | Web:         http://www.foam-extend.org
     \\/     M anipulation  | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
    This file is part of foam-extend.

    foam-extend is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    foam-extend is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.

Description
    Tetrahedral point field decomposer.

\*---------------------------------------------------------------------------*/

#include "tetPointFieldDecomposer.H"
#include "typeInfo.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{

// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //

// Calculate point addressing
void tetPointFieldDecomposer::calcAddressing() const
{
    if (directAddressingPtr_)
    {
        FatalErrorIn
        (
            "void tetPointFieldDecomposer::calcAddressing() const"
        )   << "addressing already calculated"
            << abort(FatalError);
    }

    // Allocate the addressing
    directAddressingPtr_ = new labelList(processorMesh_.nPoints(), -1);
    labelList& addr = *directAddressingPtr_;

    label nAddr = 0;

    // Insert point addressing

    // Use only live points.  HJ, 14/Apr/2009
    for (label pointI = 0; pointI < processorMesh_().nPoints(); pointI++)
    {
        addr[nAddr] = pointAddressing_[pointI];
        nAddr++;
    }

    // Insert face addressing.  Only for face decomposition
    const label faceOffset = originalMesh_.faceOffset();

    // Use only live faces.  HJ, 14/Apr/2009
    for (label faceI = 0; faceI < processorMesh_().nFaces(); faceI++)
    {
        // Remember to decrement the index by one (turning index)
        addr[nAddr] = faceOffset + mag(faceAddressing_[faceI]) - 1;
        nAddr++;
    }

    // Insert cell addressing
    const label cellOffset = originalMesh_.cellOffset();

    forAll (cellAddressing_, cellI)
    {
        addr[nAddr] = cellOffset + cellAddressing_[cellI];
        nAddr++;
    }
}


const labelList& tetPointFieldDecomposer::directAddressing() const
{
    if (!directAddressingPtr_)
    {
        calcAddressing();
    }

    return *directAddressingPtr_;
}


// Calculate patch addressing
void tetPointFieldDecomposer::
tetPolyPatchFieldDecomposer::calcPatchAddressing() const
{
    if (directPatchAddressingPtr_)
    {
        FatalErrorIn
        (
            "void tetPointFieldDecomposer::"
            "tetPolyPatchFieldDecomposer::calcPatchAddressing() const"
        )   << "addressing already calculated"
            << abort(FatalError);
    }

    // Allocate the addressing
    directPatchAddressingPtr_ = new labelList(targetPatch().size(), -1);
    labelList& addr = *directPatchAddressingPtr_;

    // Algorithm:
    // Go to the source patch, create a lookup list the size of all
    // points in the mesh and then gather the points for the current
    // patch.
    labelList pointLookup
        (sourcePatch().boundaryMesh().mesh().nPoints(), -1);

    const labelList& sourcePatchPoints = sourcePatch().meshPoints();

    forAll (sourcePatchPoints, pointI)
    {
        pointLookup[sourcePatchPoints[pointI]] = pointI;
    }

    // Gather the information

    const labelList& targetPatchPoints = targetPatch().meshPoints();

    forAll (targetPatchPoints, pointI)
    {
        addr[pointI] =
            pointLookup[directAddressing_[targetPatchPoints[pointI]]];
    }

    if (addr.size() && min(addr) < 0)
    {
        FatalErrorIn
        (
            "void tetPointFieldDecomposer::"
            "tetPolyPatchFieldDecomposer::calcPatchAddressing() const"
        )   << "error in addressing"
            << abort(FatalError);
    }
}


// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

// Construct from components
tetPointFieldDecomposer::tetPointFieldDecomposer
(
    const tetPolyMesh& originalMesh,
    const tetPolyMesh& processorMesh,
    const labelList& pointAddressing,
    const labelList& faceAddressing,
    const labelList& cellAddressing,
    const labelList& boundaryAddressing
)
:
    originalMesh_(originalMesh),
    processorMesh_(processorMesh),
    pointAddressing_(pointAddressing),
    faceAddressing_(faceAddressing),
    cellAddressing_(cellAddressing),
    boundaryAddressing_(boundaryAddressing),
    patchFieldDecompPtrs_
    (
        processorMesh_.boundary().size(),
        reinterpret_cast<tetPolyPatchFieldDecomposer*>(0)
    ),
    directAddressingPtr_(nullptr)
{
    // Set the patch field decomposers for all non-processor patch fields
    forAll (boundaryAddressing_, patchI)
    {
        if (boundaryAddressing_[patchI] >= 0)
        {
            patchFieldDecompPtrs_[patchI] =
                new tetPolyPatchFieldDecomposer
                (
                    originalMesh_.boundary()[boundaryAddressing_[patchI]],
                    processorMesh_.boundary()[patchI],
                    directAddressing()
                );
        }
        // for processor patches the pointer stays null
    }
}


// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //

tetPointFieldDecomposer::~tetPointFieldDecomposer()
{
    forAll (patchFieldDecompPtrs_, patchI)
    {
        if (patchFieldDecompPtrs_[patchI] != nullptr)
        {
            delete(patchFieldDecompPtrs_[patchI]);
            patchFieldDecompPtrs_[patchI] = nullptr;
        }
    }
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

} // End namespace Foam

// ************************************************************************* //
